#ifndef REVSURF_H_
#include "revSurf.h"
#endif

using namespace std;
using std::vector;

revSurf :: revSurf(vector<float>* Points){
 controlPoints = new vector<float>();
 controlPoints->insert(controlPoints->end(), Points->begin(), Points->end());

 vectorPerp[0] = 0;
 vectorPerp[1] = 0;
 vectorPerp[2] = 1;

 surface = new vector<float>();
 normals = new vector<float>();
 createSurface();
}

revSurf :: revSurf(){
 delete(controlPoints);
 delete(normals);
 delete(surface);
}

void revSurf :: createSurface(){

 BSplineCuadCurve curve(controlPoints,vectorPerp);
 curve.getCurve(surface);
 curve.getNormals(normals);

 largoCurva = curve.getSize();
 for(size_t i=1 ; i<=360 ; i+=DELTAREVSURF){

	rotateCtrlPoints((float)i);

 	BSplineCuadCurve curve(controlPoints,vectorPerp);
	curve.getCurve(surface);
 	curve.getNormals(normals);
 }
}

void revSurf :: rotateCtrlPoints(float angle){
 glm::mat4 rot = rotateY(angle);

 glm::vec4 Position = transform(rot,vectorPerp[0],vectorPerp[1],vectorPerp[2]);
 vectorPerp[0] = Position[0];
 vectorPerp[1] = Position[1];
 vectorPerp[2] = Position[2];

 for(size_t i=0 ; i<controlPoints->size() ; i+=3){
	glm::vec4 Position = transform(rot,(*controlPoints)[i],(*controlPoints)[i+1],(*controlPoints)[i+2]);
	(*controlPoints)[i]   = Position[0];
	(*controlPoints)[i+1] = Position[1];
	(*controlPoints)[i+2] = Position[2];
 }
}

// transforms the position using the transformation matrix
glm::vec4 revSurf :: transform(glm::mat4 transfMat,float x, float y, float z){

  glm::vec4 Position = glm::vec4(x,y,z,1.0f);
  return Position*transfMat;
}

// returns the matrix to rotate arround y axis
glm::mat4 revSurf :: rotateY(float ang){

  glm::mat4  Ry = glm::mat4(glm::vec4((float)cos(ang), 0.0f, (float)-sin(ang), 0.0f),
			    glm::vec4(           0.0f, 1.0f,             0.0f, 0.0f),
			    glm::vec4((float)sin(ang), 0.0f,  (float)cos(ang), 0.0f),
			    glm::vec4(           0.0f, 0.0f,             0.0f, 1.0f));
 return Ry;
}

void revSurf :: drawSurface(glm::mat4 mat){
 glPointSize(1.0);
 glBegin(GL_POINTS);
 for (float t=0; t< surface->size()-largoCurva-1 ;t+=3){	
		glm::vec4 Position = glm::vec4((*surface)[t],(*surface)[t+1],(*surface)[t+2],1.0f) * mat;
 		glVertex3f(Position[0],Position[1],Position[2]);

		glm::vec4 Position2 = glm::vec4((*surface)[t+largoCurva],(*surface)[t+largoCurva+1],(*surface)[t+largoCurva+2],1.0f) * mat;
 		glVertex3f(Position2[0],Position2[1],Position2[2]);
 }
 glEnd();
}

void revSurf :: drawNormals(glm::mat4 mat){
 
 for (size_t i=0 ; i<surface->size()-3 ; i+=3){
		glBegin(GL_LINES);

		glm::vec4 Position = glm::vec4((*surface)[i],(*surface)[i+1],(*surface)[i+2],1.0) * mat;
 		glVertex3f(Position[0],Position[1],Position[2]);

		glm::vec4 Position2 = glm::vec4((*surface)[i]+(*normals)[i],(*surface)[i+1]+(*normals)[i+1],(*surface)[i+2]+(*normals)[i+2],1.0) * mat;
 		glVertex3f(Position2[0],Position2[1],Position2[2]);
	
		 glEnd();

		if( (i%largoCurva) == 0)
			i+= largoCurva*DETAILNORMALSREVSURF;
  }
}

void revSurf :: drawCurve(glm::mat4 mat){
 BSplineCuadCurve curve(controlPoints,vectorPerp);
 curve.drawCurve(mat);
 curve.drawNormals();
}

void revSurf :: drawControlPoints(){
 glBegin(GL_LINE_STRIP);
 for (float t=0; t< controlPoints->size() ;t+=3)	
		glVertex3f((*controlPoints)[t],(*controlPoints)[t+1],(*controlPoints)[t+2]);
 glEnd();
}
